import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';

class AnimaPage2 extends StatefulWidget {
  @override
  _AnimaPage2State createState() => _AnimaPage2State();
}

class _AnimaPage2State extends State<AnimaPage2>
    with SingleTickerProviderStateMixin {
  final double width = 250;
  final double height = 250;

  AnimationController controller;
  Animation animation;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 500),
    );

    animation = CurvedAnimation(
      parent: controller,
      curve: Curves.easeInSine,
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('anima page 2')),
      body: Container(
        color: Colors.blueAccent,
        child: CRAnimation(
          minR: 100,
          maxR: 250,
          animation: animation,
          child: Center(
            child: Container(
              alignment: Alignment.center,
              height: this.height,
              width: this.width,
              color: Colors.greenAccent,
              child: Text("123123123"),
            ),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (controller.status == AnimationStatus.completed ||
              controller.status == AnimationStatus.forward) {
            controller.reverse();
          } else {
            controller.forward();
          }
        },
        child: Text("点我"),
      ),
    );
  }
}

class CRAnimation extends StatelessWidget {
  final double minR;
  final double maxR;
  final Widget child;
  final Animation<double> animation;

  CRAnimation({
    @required this.child,
    @required this.animation,
    this.minR,
    this.maxR,
  });

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: animation,
      builder: (context, child) {
        return ClipPath(
          clipper: AnimationClipper(
            value: animation.value,
            minR: minR,
            maxR: maxR,
          ),
          child: this.child,
        );
      },
    );
  }
}

class AnimationClipper extends CustomClipper<Path> {
  final double value;
  final double minR;
  final double maxR;
  final Offset offset;

  AnimationClipper({this.value, this.minR, this.maxR, this.offset});

  @override
  bool shouldReclip(CustomClipper oldClipper) => true;

  @override
  getClip(Size size) {
    Path path = Path();
    Offset offset = Offset(size.width / 2, size.height / 2);
    double maxRadius = maxR ?? radiusSize(size, offset);
    double minRadius = minR ?? 0;
    double radius = lerpDouble(maxRadius, minRadius, value);
    Rect rect = Rect.fromCircle(
      radius: radius,
      center: offset,
    );
    path.addOval(rect);

    return path;
  }

  double radiusSize(Size size, Offset offset) {
    final height = max(offset.dy, size.height - offset.dy);
    final width = max(offset.dx, size.width - offset.dx);

    return sqrt(width * width + height * height);
  }
}
